UseOriginCacheControlHeaders マネージドポリシーの Host キャッシュキー指定による挙動を調べてみた
いわさです。
先日 CloudFront に新しいマネージドキャッシュポリシーが登場しました。
雑に言うとオリジンの Cache-Control ヘッダーを尊重するよというポリシーです。
ほーいいじゃないか、こういうのでいいんだよ。と思いながら私も早速使ってみたところ...
% curl https://d1uqy558jl7bhw.cloudfront.net/ -i
HTTP/2 403
content-type: application/json
content-length: 23
date: Wed, 10 Jul 2024 06:15:08 GMT
x-amzn-requestid: f05dff6b-3778-49dd-989f-ef06f37ad99e
x-amzn-errortype: ForbiddenException
x-amz-apigw-id: arsE-F0DNjMELOQ=
x-cache: Error from cloudfront
via: 1.1 6bdff89d7edf793d60fc3af5190198de.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT20-C2
x-amz-cf-id: vt9mUKe5gvcsw3C8xW9SFX1K4r4L1UcNZEOuqesgwWZsIKTmTILmwA==
{"message":"Forbidden"}
なぜか 403 エラーに。
この時のオリジンは Lambda 関数 URL を使ったのですがメトリクスを見る限りでは関数自体の Invoke がされていないようです。
この挙動を調べるために色々なオリジンタイプを用意して検証してみましたので、その様子を紹介したいと思います。
オリジンタイプを用意
CloudFront はドメイン名からオリジンタイプを自動検出してくれます。
オリジンタイプによって挙動が変わるのか?と思い次のように複数のオリジンをまず用意しました。
まずは CloudFront を経由せずにオリジンに直接アクセスしてみます。
次のようなイメージです。
試してみたところ当然ながら問題はありませんでした。
# ALB-EC2
% curl hoge-web-alb-1355127211.ap-northeast-1.elb.amazonaws.com -I
HTTP/1.1 200 OK
Date: Wed, 10 Jul 2024 05:43:00 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 5
Connection: keep-alive
Server: Apache/2.4.59 ()
Upgrade: h2,h2c
Last-Modified: Wed, 10 Jul 2024 05:41:30 GMT
ETag: "5-61cde19211f1b"
Accept-Ranges: bytes
Cf-Team: 213cc3b7990000e02170394400000001
# checkip.amazonaws.com
% curl checkip.amazonaws.com -I
HTTP/1.1 200
Date: Wed, 10 Jul 2024 05:43:10 GMT
Content-Type: text/plain;charset=UTF-8
Content-Length: 14
Connection: keep-alive
Server: nginx
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Cf-Team: 213cc3ddbf0000e021703ea400000001
# hoge0710aaa (API Gateway)
% curl https://7uma0fumhd.execute-api.ap-northeast-1.amazonaws.com/hoge0710/hoge -I
HTTP/2 200
date: Wed, 10 Jul 2024 05:43:55 GMT
content-type: application/json
content-length: 40
x-amzn-requestid: 7d4cea6d-9ede-44d0-aba2-728a5aa601fb
x-amzn-remapped-content-length: 40
x-amz-apigw-id: arngWGKUtjMEveg=
x-amzn-trace-id: Root=1-668e1f9b-093f5df56250c1ea629d1e6e;Parent=030fd577aab66d85;Sampled=0;lineage=3a6ed96b:0
# lambdaUrl
% curl https://gyduqyxzbykh7bsjmytdgmbmje0tfmpb.lambda-url.ap-northeast-1.on.aws/ -I
HTTP/1.1 200 OK
Date: Wed, 10 Jul 2024 05:44:38 GMT
Content-Type: application/json
Content-Length: 0
Connection: keep-alive
x-amzn-RequestId: c23ff03c-8d9a-41a8-8d26-02d73f6ebeff
X-Amzn-Trace-Id: root=1-668e1fc6-464f21c65d456ec27f55d14d;parent=53939bb02ccbc74e;sampled=0;lineage=3a6ed96b:0
# lightsail (Custom Origin)
% curl http://hoge-iwasa.net/ -I
HTTP/1.1 200 OK
Date: Wed, 10 Jul 2024 05:45:52 GMT
Server: Apache
Last-Modified: Mon, 17 Jun 2024 11:45:43 GMT
ETag: "1303-61b14814f07c0"
Accept-Ranges: bytes
Content-Length: 4867
Vary: Accept-Encoding
Content-Type: text/html
Cf-Team: 213cc657c10000e021709db400000001
# S3 Static WebSite
% curl http://iwasa-hoge-public-bucket.s3-website-ap-northeast-1.amazonaws.com/ -I
HTTP/1.1 200 OK
x-amz-id-2: ccLlRiq++mZMdTOroQfO5Qo3AGV4LoeFPNCG8PM8x/HbWYqQNJhEz7pZEpU5mitCmE+HZ3rpzRM=
x-amz-request-id: 1K1NR9YSC0T15S9G
Date: Wed, 10 Jul 2024 05:46:01 GMT
Last-Modified: Mon, 30 May 2022 23:34:56 GMT
ETag: "2d9191d1c2b2d6b7739df4ca3b818b25"
Content-Type: text/html
Server: AmazonS3
Content-Length: 10
Cf-Team: 213cc676460000e02170a1f400000001
続いてそれぞれのオリジンを CloudFront 経由でアクセスしてみましょう。
キャッシュポリシーは今回使いたかった UseOriginCacheControlHeaders を、オリジンリクエストポリシーは AllViewerExceptHostHeader を選択しました。
オリジンリクエストポリシーについては Host ヘッダーさえ転送されなければ今回の検証範囲では不都合は起きないはずです。
先ほどと同じようにリクエストを送信してみます。
# ALB-EC2
% curl https://d1uqy558jl7bhw.cloudfront.net/ -I
HTTP/2 200
:
# checkip.amazonaws.com
% curl https://d1uqy558jl7bhw.cloudfront.net/ -I
HTTP/2 200
:
# API Gateway
% curl https://d1uqy558jl7bhw.cloudfront.net/ -I
HTTP/2 403
content-type: application/json
content-length: 23
date: Wed, 10 Jul 2024 06:14:23 GMT
x-amzn-requestid: 82bdfae9-11f1-4e09-82cf-8abac4642223
x-amzn-errortype: ForbiddenException
x-amz-apigw-id: arr-BFMoNjMEYog=
x-cache: Error from cloudfront
via: 1.1 4f7d123e12a6d79006c5c9bf3e1ce47a.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT20-C2
x-amz-cf-id: Z_CsFR2oGYyNmsWU5IBiNYlv9dWsiZY6HsXkuWrMBgg4W8aBL3Vo-g==
:
# Lambda Function URL
% curl https://d1uqy558jl7bhw.cloudfront.net/ -I
HTTP/2 403
content-type: application/json
content-length: 23
date: Wed, 10 Jul 2024 06:15:08 GMT
x-amzn-requestid: f05dff6b-3778-49dd-989f-ef06f37ad99e
x-amzn-errortype: ForbiddenException
x-amz-apigw-id: arsE-F0DNjMELOQ=
x-cache: Error from cloudfront
via: 1.1 6bdff89d7edf793d60fc3af5190198de.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT20-C2
x-amz-cf-id: vt9mUKe5gvcsw3C8xW9SFX1K4r4L1UcNZEOuqesgwWZsIKTmTILmwA==
:
# Custom Origin
% curl https://d1uqy558jl7bhw.cloudfront.net/ -I
HTTP/2 200
:
# S3 Static Web
% curl https://d1uqy558jl7bhw.cloudfront.net/ -I
HTTP/2 404
content-type: text/html; charset=utf-8
content-length: 376
date: Wed, 10 Jul 2024 06:21:21 GMT
server: AmazonS3
x-cache: Error from cloudfront
via: 1.1 d4ec4fe8ac7dc1717cdfe6977662568e.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT20-C2
x-amz-cf-id: pbSfeJxRVsbhk_D4LsQWHzvGJ7dDTH9czurKuuYNrZTwMFbk-wYHIg==
age: 1
API Gateway、Lambda 関数 URL、S3 静的ホスティングで問題が生じていますね。
ただ、ELB-EC2 や Lightsail のカスタムオリジンだと問題なく動作しているように見えます。うーん?
ちなみに上記に対して次のように別のマネージドポリシーを設定した場合は問題なく動作しますのでビヘイビアやオリジンの基本設定に問題がある感じではなさそうです。
host ヘッダーが送信されていた
そしてその後調べていて気がついたのですが、S3 静的ホスティングの Body エラーメッセージを確認してみると次のようなレスポンスが取得されていました。
% curl https://d1uqy558jl7bhw.cloudfront.net/
<html>
<head><title>404 Not Found</title></head>
<body>
<h1>404 Not Found</h1>
<ul>
<li>Code: NoSuchBucket</li>
<li>Message: The specified bucket does not exist</li>
<li>BucketName: d1uqy558jl7bhw.cloudfront.net</li>
<li>RequestId: SNQBJN7MA3APA8V8</li>
<li>HostId: lXpeRk6OOiNT9XxuR3UMM2K+06+VT74Nng+ImK9KkkxnEgz5/KwZhp5lE/OIY6hHCrjIlO6Hj34=</li>
</ul>
<hr/>
</body>
</html>
バケットが存在しないと言われていますね。そしてバケット名が CloudFront ディストリビューションのドメインです。これか。
ここでようやく UseOriginCacheControlHeaders マネージドキャッシュポリシーのキャッシュキーに host が含まれていることに気が付きました。
キャッシュポリシーのキャッシュキーは自動でオリジンリクエストに追加されるので、AllViewerExceptHostHeader ポリシーを使ってもビューアの Host ヘッダーが転送されるというわけですね。なんてこったい。
結局カスタムキャッシュポリシーを作成しました
で、このマネージドポリシーは編集出来そうに見えるのですが...
やってみると変更は許可されていないとエラーメッセージが表示されます。
というわけでカスタムキャッシュポリシーを作りました。
内容は同じで、キャッシュキーから host ヘッダーだけ除きました。
このカスタムキャッシュポリシーを設定すると期待どおり動作しました。
Cache-Control ヘッダーの設定に準拠して CloudFront のキャッシュをコントロール出来るようになりました。
ちなみに Lambda 関数 URL では次のようにmax-age
で調整したり試してみました。
export const handler = async (event) => {
const response = {
statusCode: 200,
headers: {
'Cache-Control': 'public, max-age=5'
},
body: JSON.stringify({timestamp: new Date()}),
};
return response;
};
% curl https://d1uqy558jl7bhw.cloudfront.net/
{"timestamp":"2024-07-10T08:16:18.225Z"}
% curl https://d1uqy558jl7bhw.cloudfront.net/
{"timestamp":"2024-07-10T08:16:18.225Z"}
% curl https://d1uqy558jl7bhw.cloudfront.net/
{"timestamp":"2024-07-10T08:16:23.149Z"}
% curl https://d1uqy558jl7bhw.cloudfront.net/
{"timestamp":"2024-07-10T08:16:23.149Z"}
% curl https://d1uqy558jl7bhw.cloudfront.net/
{"timestamp":"2024-07-10T08:16:23.149Z"}
% curl https://d1uqy558jl7bhw.cloudfront.net/
{"timestamp":"2024-07-10T08:16:28.547Z"}
% curl https://d1uqy558jl7bhw.cloudfront.net/
{"timestamp":"2024-07-10T08:16:28.547Z"}
なお、Cache-Control ヘッダーの仕様についてこちらを参考にさせて頂いております。
さいごに
本日は UseOriginCacheControlHeaders マネージドポリシーの Host キャッシュキー指定による挙動を調べてみました。
キャッシュキーの host が必要なのか?はちょっと疑問なのですが、このケースの host ヘッダー転送は期待した挙動にならないことが多い気もするので、修正されるような気もしています。
いずれにせよマネージドポリシーが期待どおり動作しない場合もカスタムポリシーを作ることで回避出来ることが多いので覚えておきましょう。